home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr35 / dwnsrs57.zip / DOWNCOL.C < prev    next >
C/C++ Source or Header  |  1993-06-18  |  51KB  |  1,032 lines

  1. /* ============================================================ */
  2. /*  Rob Hamerling's MAXIMUS download file scan and sort utility. */
  3. /*  -> DOWNCOL.C                                                 */
  4. /*  -> Functions to collect download file information.           */
  5. /* ============================================================= */
  6.  
  7. /* #define __DEBUG__ */
  8.  
  9. #define INCL_DOS
  10. #define INCL_DOSFILEMGR
  11. #define INCL_DOSERRORS
  12. #define INCL_NOPMAPI
  13. #include <os2.h>
  14.  
  15. #include <conio.h>
  16. #include <fcntl.h>
  17. #include <io.h>
  18. #include <malloc.h>
  19. #include <share.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <sys\types.h>
  24.  
  25. #include "..\max\mstruct.h"             /* MAXIMUS definitions          */
  26. #include "downsort.h"                   /* downsort defines             */
  27. #include "downfpro.h"                   /* downsort function prototypes */
  28.  
  29.  
  30. /* prototypes of local function functions */
  31.  
  32. void       add_to_chain(FILECHAIN **cp, FILECHAIN *tp);
  33. int        area_selection(char *, char [][MAXANAME]);
  34. FILECHAIN *add_comment(char *, DOWNPATH _HUGE *,
  35.                         char *, short int, unsigned short int);
  36. void       add_pathspec(char  *, FILECHAIN *);
  37. FILECHAIN *assign_desc(short int, char *, FILECHAIN **,
  38.            DOWNPATH _HUGE *, char *, short int, USHORT);
  39. char      *build_desc(FILE *, char *, char **);
  40. USHORT     combine_comments(void);
  41. FILECHAIN *desc_dup(FILECHAIN *, char *,
  42.                DOWNPATH _HUGE *, short int, USHORT, USHORT, USHORT);
  43. USHORT      fill_chn(DOWNPATH _HUGE *, FILECHAIN **);
  44. FILECHAIN  *file_element(DOWNPATH _HUGE *,
  45. #ifndef __32BIT__
  46.                          FILEFINDBUF *);
  47. #else
  48.                          FILEFINDBUF3 *);
  49. #endif
  50. USHORT      free_orphan(void);
  51. USHORT      get_desc(DOWNPATH _HUGE *, FILECHAIN **);
  52. char       *parse_fname(char *);
  53. int         sort_path(const void *, const void *);
  54. int         split_fname(char *);
  55.  
  56.  
  57. /* ---------------------------- */
  58. /* Collect download file area's */
  59. /* ---------------------------- */
  60. unsigned short int collect_area(DOWNPATH _HUGE **area)
  61. {
  62. #ifndef __32BIT__
  63.   FILESTATUS  fs;                       /* file status buffer            */
  64.   unsigned short int
  65. #else
  66.   FILESTATUS3 fs;                       /* file status buffer            */
  67.   unsigned long int
  68. #endif
  69.           af, oaction;                  /* file handle, open_action      */
  70.   int     rc;                           /* returncode                    */
  71.   short   int i,j,k,m;                  /* counters                      */
  72.   struct _area a;                       /* MAXIMUS (minimum) area struct.*/
  73.   DOWNPATH _HUGE *d;                    /* ptr to array with area-info   */
  74.  
  75.   rc = DosOpen(areadat_path,            /* open 'carefully'              */
  76.           &af,                          /* pointer to File Handle        */
  77.           &oaction,                     /* pointer to action field       */
  78.           0L,                           /* new filesize (N/A)            */
  79.           FILE_NORMAL,                  /* attributes                    */
  80.           FILE_OPEN,                    /* open flags                    */
  81.           OPEN_ACCESS_READONLY    |     /* mode                          */
  82.             OPEN_SHARE_DENYWRITE,
  83.           0L);                          /* no EA's                       */
  84.   if (rc != NO_ERROR) {                 /* open error                    */
  85.     fprintf(stderr, MSG_OPI, areadat_path, rc);
  86.     DosExit(0, rc);
  87.     }
  88.   if (oaction != FILE_EXISTED) {        /* not found                     */
  89.     fprintf(stderr, MSG_OPA, areadat_path, oaction);
  90.     DosExit(0, 5);
  91.     }
  92.   else {
  93.     if (oper_mode != QUIET)
  94.       fprintf(stdout, MSG_COA, areadat_path);
  95. #ifndef __32BIT__
  96.     rc = DosQFileInfo(af, 1, &fs, sizeof(fs)); /* get info of AREA.DAT   */
  97. #else
  98.     rc = DosQueryFileInfo(af, 1, &fs, sizeof(fs)); /* get info AREA.DAT  */
  99. #endif
  100.     read(af,(char *)&a,sizeof(struct _area));  /* obtain first part      */
  101.     m = 0;                              /* init participating file count */
  102.     if (a.id != AREA_id) {              /* validate MAXIMUS format       */
  103.       fprintf(stderr, MSG_MX1, areadat_path);
  104.       fprintf(stderr, MSG_MX2, PROGNAME,VERSION,SUBVERS,SUFFIX,MAX);
  105.       }
  106.     else {                              /* acceptable AREA.DAT           */
  107.       k = (short int)(fs.cbFile / a.struct_len);  /* # area's            */
  108.       for (i=0; i<k; i++) {             /* count area's with downloads   */
  109.         lseek(af, i*(long)a.struct_len, SEEK_SET);  /* locate to next    */
  110.         read(af, (char *)&a, sizeof(struct _area));
  111.         if (a.filepath[0] != '\0'       &&
  112.             a.filepath[0] != ' '        &&
  113.             a.filepriv <= ABS_MAX_priv  &&   /* within report privilege  */
  114.             area_selection(a.name, selected_area))   /* not excluded     */
  115.           m++;                          /* participating filearea count  */
  116.         }
  117.       if (m > 0) {                      /* any area's participating      */
  118. #ifndef __32BIT__
  119.         d = (DOWNPATH _HUGE *)halloc(m, sizeof(DOWNPATH));
  120. #else
  121.         d = (DOWNPATH *)malloc(m * sizeof(DOWNPATH));
  122. #endif
  123.         if (d == NULL) {                /* memory not obtained?          */
  124.           fprintf(stderr, MSG_MEM, PROGNAME);
  125.           DosExit(0, 6);
  126.           }
  127.         else {                          /* have memory for area-info     */
  128.           *area = d;                    /* set return pointer            */
  129.           for (i=m=0; i<k; i++) {       /* all area's                    */
  130.             lseek(af, i*(long)a.struct_len, SEEK_SET);  /* locate to next*/
  131.             read(af, (char *)&a, sizeof(struct _area));
  132.             if ( a.filepath[0] != '\0'      &&  /* filename(?)           */
  133.                  a.filepath[0] != ' '       &&  /* filename(?)           */
  134.                  a.filepriv <= ABS_MAX_priv &&  /* within report privileg*/
  135.                  area_selection(a.name, selected_area)) {  /* selected   */
  136.               d[m].priv = a.filepriv;           /* download privilege    */
  137.               strcpy(d[m].name, a.name);        /* area name ... edit!   */
  138.               d[m].anum = i;                    /* AREA.DAT seq. nbr     */
  139.               d[m].file_count = 0;              /* init file count       */
  140.               d[m].byte_count = 0L;             /* init byte count       */
  141.               d[m].newest     = NULL;           /* pointer to newest file*/
  142.               strcpy(d[m].pname, a.filepath);   /* download path         */
  143.               j = strlen(d[m].pname);
  144.               if (j>0 && d[m].pname[j-1] != '\\')
  145.                 d[m].pname[j] = '\\';           /* backslash if needed   */
  146.               strcpy(d[m].filesbbs, a.filesbbs); /* files.bbs            */
  147.               strcpy(d[m].adesc, a.fileinfo);   /* filearea title        */
  148.               ++m;                              /* filearea index        */
  149.               }
  150.             }
  151.           }
  152.         /* manipulate here area-names for 'intelligent' sorting          */
  153.         max_aname = 0;                  /* init max areaname length      */
  154.         for (i=0; i<m; i++)             /* all collected area's          */
  155.           max_aname = max(strlen(d[i].name), max_aname);
  156.         for (i=0; i<m; i++) {           /* all collected area's          */
  157.           sprintf(d[i].ename,
  158.                  (d[i].name[0]<'0' || d[i].name[0]>'9')  /* not num      */
  159.                     ? "%-*.*s" : "%*.*s",  /* left or right aligned      */
  160.                   max_aname, max_aname, d[i].name);
  161.           d[i].ename[max_aname] = '\0'; /* end of string                 */
  162.           j = k = max_aname-1;          /* init offset values            */
  163.           while (j>=0 && d[i].ename[j] == ' ')  /* search last char      */
  164.             j--;
  165.           if (j < k) {                  /* spaces found                  */
  166.             while (j>=0               &&
  167.                    d[i].ename[j]>='0' &&
  168.                    d[i].ename[j]<='9') {
  169.               d[i].ename[k--] = d[i].ename[j];  /* move                  */
  170.               d[i].ename[j--] = ' ';            /* replace by blank      */
  171.               }
  172.             }
  173.           }
  174. #if defined(__DEBUG__)
  175.         dump_area_array(d,m,"check on ename editing");
  176. #endif
  177.         }
  178.       }
  179.     DosClose(af);                       /* close area.dat-file           */
  180.     return(m);                          /* report number downloadarea's  */
  181.     }
  182.   }
  183.  
  184. /* ---------------------------- */
  185. /* Collect all file information */
  186. /* ---------------------------- */
  187. unsigned int collect_file(unsigned int a,
  188.                           DOWNPATH _HUGE *area)
  189. {
  190.   unsigned short int  i,k,l,fc,orphan_count;   /* counters               */
  191.   FILECHAIN *ca,*ce;            /* ptrs to file info             */
  192.  
  193.   fc = orphan_count = 0;                /* init file and orphan count    */
  194.   if (oper_mode != QUIET)
  195.     fprintf(stdout, MSG_COF);
  196.   qsort(area, a, sizeof(DOWNPATH), sort_path);
  197.                          /* WARNING: do no sort again in this array!     */
  198.   for (i=0; i<a; i++) {                 /* all 'included' download areas */
  199.     if (oper_mode == VERBOSE)
  200.       fprintf(stdout, MSG_ARE, area[i].pname, area[i].name);
  201.     else if (oper_mode != QUIET)
  202.       fprintf(stdout, DOT);
  203.     fflush(stdout);                     /* show output                   */
  204.  
  205.     if (i<1 || stricmp(area[i].pname, area[i-1].pname)) {  /* pathnames  */
  206.       if (lp[P_ORP].priv[0] > HIDDEN)   /* orphan report not req'd       */
  207.         orphan_count += free_orphan();  /* free orphans still in chain   */
  208.       ca = NULL;                        /* for new directory             */
  209.       k = fill_chn(&area[i], &ca);      /* read directory                */
  210.                                         /* returns #files + ptr to first */
  211.       fc += k;                          /* add to total                  */
  212.       if (ca!=NULL) {                   /* any files in group            */
  213.         if ((ce = first_element) != NULL) {  /* not empty chain          */
  214.            while (ce->next_element != NULL) /* find last element         */
  215.              ce = ce->next_element;
  216.            ce->next_element = ca;       /* couple new group to chain     */
  217.            }
  218.         if (first_element==NULL)        /* first non-empty group         */
  219.           first_element = ca;           /* set pointer to head of chain  */
  220.         }
  221.       }
  222.     if (oper_mode==VERBOSE)
  223.       fprintf(stdout, " %5d\n",k);      /* total this download path      */
  224.     l = get_desc(&area[i], &ca);        /* obtain descriptions           */
  225.     if (oper_mode==VERBOSE && l>0) {    /* any offline files found       */
  226.       fprintf(stdout, MSG_ARE, area[i].pname, area[i].name);
  227.       fprintf(stdout, " %5d\n", k += l); /* value after get_desc      */
  228.       }
  229.     fc += l;                            /* add 'extra' filecount         */
  230.     if (first_element==NULL)            /* very first                    */
  231.       first_element = ca;               /* set pointer to head of chain  */
  232.     }                                   /* all area's processed          */
  233.  
  234.   if ((ca = first_element) != NULL) {   /* any files                     */
  235.     if (lp[P_ORP].priv[0] > HIDDEN) {   /* orphan report not req'd       */
  236.       orphan_count += free_orphan();    /* free any left orphans         */
  237.       if (ca->priv >= HIDDEN) {         /* first is an orphan            */
  238.         first_element=ca->next_element; /* new ptr to first              */
  239.         free(ca);                       /* free memory block             */
  240.         ++orphan_count;                 /* one more dropped              */
  241.         }
  242.       }
  243.     }
  244.   if (oper_mode==VERBOSE && orphan_count>0)
  245.     fprintf(stdout, MSG_ORP, orphan_count);
  246.   else if (oper_mode!=QUIET)
  247.     fprintf(stdout,"\n");               /* newline..flush */
  248.  
  249.   fc -= orphan_count;                   /* less dropped orphans          */
  250.  
  251. #if defined(__DEBUG__)
  252.   dump_file_chain(first_element, " --> after all areas");
  253. #endif
  254.  
  255.   if (fc) {                             /* file(s) present               */
  256.     k=0;                                /* init count                    */
  257.     if ((ca = first_element) != NULL) { /* pointer to first element      */
  258.       ++k;                              /* at least 1                    */
  259.       while (ca->next_element != NULL) { /* find last                    */
  260.         ++k;                            /* another element               */
  261.         ca = ca->next_element;          /* pointer to next               */
  262.         }
  263.       }
  264.     if (fc != k) {                      /* compare counts                */
  265.       fprintf(stderr, MSG_IEC, fc, k);  /* counter values                */
  266.       DosExit(0, 99);                   /* quit on error                 */
  267.       }
  268.     }
  269.   return(fc);                           /* file total count              */
  270.   }
  271.  
  272. /* ---------------------------------------- */
  273. /* Add all subdir-filenames to the chain,   */
  274. /* for further processing by mainline.      */
  275. /* NOTE: - full path name assumed!          */
  276. /* returns number of files in this area     */
  277. /* ---------------------------------------- */
  278. unsigned short int fill_chn(DOWNPATH _HUGE *parea,
  279.                             FILECHAIN **cp)
  280. {
  281.   int      rc;                          /* returncode of DOS-calls       */
  282.   unsigned short int fc;                /* area-file counter             */
  283.   FILECHAIN *ca,*ce,*tp;                /* new, curr, temp, chain ptrs   */
  284.   char   down_spec[MAXPATH];            /* file specification buffer     */
  285.   HDIR   fhandle = HDIR_CREATE;         /* FindFirst/Last handle         */
  286. #ifndef __32BIT__
  287.   FILEFINDBUF  cf;                      /* file-info buffer              */
  288.   unsigned int fentries;                /* # entries to be retrieved     */
  289. #else
  290.   FILEFINDBUF3 cf;                      /* file-info buffer              */
  291.   unsigned long int fentries;           /* # entries to be retrieved     */
  292. #endif
  293.  
  294.   fc = 0;                               /* init filecount of this area   */
  295.   fentries = 1;                         /* retreive 1 at a time (DOS!)   */
  296.   strcpy(down_spec,parea->pname);       /* path                          */
  297.   strcat(down_spec, "*.*");             /* file-spec                     */
  298.   rc = DosFindFirst(down_spec,
  299.                     &fhandle,
  300.                     FILE_NORMAL,
  301.                     &cf,
  302.                     sizeof(cf),
  303.                     &fentries,
  304. #ifndef __32BIT__
  305.                     0L);                /* unused with OS/2 < 2.0        */
  306. #else
  307.                     FILE_ARCHIVED || FILE_READONLY); /* */
  308. #endif
  309.   ca = NULL;                            /* no first in group yet         */
  310.   while (rc == 0) {
  311.     if ((wild_comp(cf.achName,"FILES.*")     != 0) &&
  312.         (wild_comp(cf.achName,"*.BAK")       != 0) &&
  313.         (wild_comp(cf.achName,"SYSTEM*.?BS") != 0) &&
  314.         (wild_comp(cf.achName,"DIR.?BS")     != 0)) {
  315.  
  316.       tp = file_element(parea, &cf);    /* add new element to chain      */
  317.                                         /* note: exits if no memory      */
  318.       if (ca == NULL)                   /* it is first element in group  */
  319.         ca = ce = tp;                   /* first and last in group       */
  320.       else {                            /* not first                     */
  321.         ce->next_element = tp;          /* chain-ptr in previous         */
  322.         ce = tp;                        /* new last in group             */
  323.         }
  324.       ++fc;                             /* update filecount this area    */
  325.       byte_count += cf.cbFile;          /* update file bytecount         */
  326.  
  327.       if (oper_mode==VERBOSE && (fc%25)==0) {  /* every 25 files         */
  328.         fprintf(stdout, " %5u\r", fc);
  329.         fflush(stdout);
  330.         }
  331.       }
  332.     fentries = 1;                       /* retreive 1 at a time (DOS!)   */
  333.     rc = DosFindNext(fhandle,
  334.                      &cf,
  335.                      sizeof(cf),
  336.                      &fentries);
  337.     }
  338.   DosFindClose(fhandle);                /* close directory association   */
  339.   *cp = ca;                             /* pointer to first new this area*/
  340.   return(fc);
  341.   }                                     /* return # of allocated elements*/
  342.  
  343. /* -------------------------------------- */
  344. /* Add file description to chain elements */
  345. /* -------------------------------------- */
  346. unsigned short int get_desc(DOWNPATH _HUGE *parea,
  347.                             FILECHAIN **cp)
  348. {
  349. #ifndef __32BIT__
  350.   unsigned short int
  351. #else
  352.   unsigned long int
  353. #endif
  354.           fih,                          /* file handle                   */
  355.           oaction;                      /* open-action flags             */
  356.   FILE   *fi;                           /* file pointer                  */
  357.   unsigned short int y;                 /* number of offline files       */
  358.   FILECHAIN *ce, *tp;                   /* ptrs to file-info             */
  359.   char   buf[MAXRCD];                   /* read-buffer for FILES.BBS     */
  360.   char   filename[MAXFN];               /* filename from FILES.BBS buf   */
  361.   char   *desc, *rp;                    /* ptr to desc / return string   */
  362.   short int  i,k,m,p,x;                 /* counters                      */
  363.   short int  fpriv;                     /* file privilege                */
  364.   int     rc;                           /* returncode                    */
  365.   int     fn_off;                       /* filename offset               */
  366.   unsigned short int bbsseq;            /* current line number FILES.BBS */
  367.   char   desc_spec[MAXPATH];
  368.   FILECHAIN **fa;               /* pointer to file sort-array    */
  369.   static char prop[4]    = "/|\\-";     /* rotating propeller            */
  370.  
  371.   if (strlen(parea->filesbbs) > 0)      /* explicit specification?       */
  372.     strcpy(desc_spec,parea->filesbbs);  /* explicitly specified FileList */
  373.   else {                                /* no                            */
  374.     strcpy(desc_spec,parea->pname);     /* get path to download directory*/
  375.     strcat(desc_spec,lp[P_FIL].name);   /* add filename                  */
  376.     strcat(desc_spec,".");              /* add separator                 */
  377.     strcat(desc_spec,lp[P_FIL].ext);    /* add extension                 */
  378.     }
  379.  
  380.   fpriv = parea->priv;                  /* area-priv is default file priv*/
  381.                                         /* FILES.BBS may be in use!!!    */
  382.   rc = DosOpen(desc_spec,               /* Open 'carefully'              */
  383.           &fih,                         /* pointer to File Handle        */
  384.           &oaction,                     /* pointer to action field       */
  385.           0L,                           /* new filesize (N/A)            */
  386.           FILE_NORMAL,                  /* attributes                    */
  387.           FILE_OPEN,                    /* open flags                    */
  388.           OPEN_ACCESS_READONLY    |     /* mode                          */
  389.             OPEN_SHARE_DENYWRITE,
  390.           0L);                          /* no EA's OS/2 2.0+             */
  391.   if (rc) {                             /* open error                    */
  392.     fprintf(stderr, MSG_OPI, desc_spec, rc);
  393.     return(0);                          /* no: return to caller          */
  394.     }
  395.   if ((fi = fdopen(fih, "r")) == NULL) {
  396.     fprintf(stderr, MSG_OPA, desc_spec, -1);   /* dummy rc             */
  397.     return(0);                          /* no: return to caller          */
  398.     }
  399.  
  400.   ce = *cp;                             /* ptr to 1st element of group   */
  401.   for (x=0; ce != NULL; x++)            /* count collected dir entries   */
  402.     ce = ce->next_element;              /* pointer to next file entry    */
  403.  
  404.   if (x > 0) {                          /* if any files in dir           */
  405.     fa = (FILECHAIN **)malloc(x * sizeof(FILECHAIN *));
  406.     if (fa == NULL) {                   /* not enough memory             */
  407.       fprintf(stderr, MSG_MEM,PROGNAME);
  408.       DosExit(0, 11);
  409.       }
  410.     ce = *cp;                           /* ptr to 1st element of group   */
  411.     for (i=0; ce != NULL; i++) {        /* init sort array               */
  412.       fa[i] = ce;                       /* element pointer into array    */
  413.       ce = ce->next_element;            /* pointer to next file entry    */
  414.       }
  415.     qsort(fa, x, sizeof(FILECHAIN *), sort_gbl);
  416.     }
  417.   else                                  /* no files in group             */
  418.     fa=NULL;                            /* no array allocated            */
  419.  
  420.   y = 0;                                /* init 'offline' counter        */
  421.   bbsseq = 0;                           /* init counter                  */
  422.   rp = fgets(buf, MAXRCD, fi);          /* get first FILES.BBS record    */
  423.   while (rp != NULL) {                  /* until end of FILES.BBS        */
  424.     bbsseq++;                           /* line counter                  */
  425.     m = strlen(buf);                    /* length of input string        */
  426.     if (m>1 && buf[0] == '\20') {       /* privilege change (^P) ?       */
  427.       for (k=0; k<HIDDEN-TWIT && priv_name[k][0]!=buf[1]; k++);
  428.       if (TWIT + k > parea->priv)       /* only if higher than area-priv */
  429.         fpriv = TWIT + k;               /* new (higher) prilivege        */
  430.       rp = fgets(buf, MAXRCD, fi);      /* continue                      */
  431.       }
  432.     else if (parse_fname(buf) == NULL) { /* NOT likely a filename        */
  433.       if ( strncmp(buf, FILPREFX, 3)==0  ||  /* Downsort header line     */
  434.            bbsseq <= 8 ) {              /* first 8 lines                 */
  435.         }                               /* just skip these               */
  436.       else if (lp[P_ALL].sortflag == KEEPSEQ ||   /* ALL-list with /K    */
  437.                lp[P_IPF].sortflag == KEEPSEQ ||   /* IPF-list with /K    */
  438.                lp[P_IP2].sortflag == KEEPSEQ ||   /* IP2-list with /K    */
  439.                (lp[P_FIL].sortflag == KEEPSEQ &&  /* FIL-list            */
  440.                 lp[P_FIL].priv[0] <= HIDDEN)) {   /*    with '/K'        */
  441.         tp = add_comment(EMPTY, parea,     /* filename = null-string     */
  442.                      buf, fpriv, bbsseq);
  443.         add_to_chain(cp, tp);           /* add element to end-of-chain   */
  444.         ++y;                            /* add 1 to 'offline' filecount  */
  445.         }
  446.       rp = fgets(buf, MAXRCD, fi);      /* continue with next line       */
  447.       }
  448.     else {                              /* probably file descr record    */
  449.       fn_off = split_fname(buf);        /* pathspec -> extra file */
  450.       for (i=fn_off;                    /* starting point of scan        */
  451.                 i < fn_off+MAXFN-1  &&  /* maximum filename length (8.3) */
  452.                 i < m               &&  /* string length                 */
  453.                 buf[i] != ' '       &&  /* space character               */
  454.                 buf[i] != '\r'      &&  /* CR character                  */
  455.                 buf[i] != '\n';         /* LF character                  */
  456.                    i++);                /* scan for filespec             */
  457.       strncpy(filename, buf+fn_off, i-fn_off);   /* select filename      */
  458.       filename[i - fn_off] = '\0';      /* end of string                 */
  459.       strupr(filename);                 /* filename in capitals          */
  460.       desc = build_desc(fi, buf, &rp);  /* build description string      */
  461.       if (desc == NULL)                 /* no description                */
  462.         rp = fgets(buf, MAXRCD, fi);    /* prepare for next file entry   */
  463.       tp = assign_desc(x, filename,     /* assign desc to file(s)        */
  464.                        fa, parea, desc, fpriv, bbsseq);
  465.       if (tp != NULL) {                 /* new element for group         */
  466.         add_to_chain(cp, tp);           /* add element to end-of-chain   */
  467.         if (fn_off > 0)                 /* pathspec -> extra file        */
  468.           add_pathspec(asciiz(buf), tp);    /* add also file-info        */
  469.         ++y;                            /* add 1 to 'extra' filecount    */
  470.         }
  471.       }
  472.     if (oper_mode == VERBOSE && (bbsseq%5) == 0) {
  473.       fprintf(stdout, "%c\r",prop[p=(++p)&3]);  /* propeller             */
  474.       fflush(stdout);
  475.       }
  476.     }
  477.   if (fa != NULL)                       /* memory for array allocated    */
  478.     free(fa);                           /* free temp sort array          */
  479.   x = combine_comments();               /* drop comment pairs            */
  480.   if (oper_mode == VERBOSE)
  481.     fprintf(stdout, " \r");             /* clear propeller               */
  482.   fclose(fi);                           /* finished with this FILES.BBS  */
  483.   DosClose(fih);                        /* close the handle              */
  484.   return(y-x);                          /* return 'offline' filecount    */
  485.                                         /* (includes comment elements)   */
  486.   }
  487.  
  488. /* -------------------------------------- */
  489. /* Add a new file element to end-of-chain */
  490. /* -------------------------------------- */
  491. void add_to_chain(FILECHAIN **cp,
  492.                   FILECHAIN *tp)
  493. {
  494.   FILECHAIN *ce;                /* work pointer                  */
  495.  
  496.   if (*cp == NULL) {                    /* group was empty               */
  497.     *cp = tp;                           /* return ptr to first in group  */
  498.     if (first_element == NULL)          /* whole chain empty             */
  499.       return;                           /* ===> nothing else to do here! */
  500.     else                                /* something in chain            */
  501.       ce = first_element;               /* ptr to very 1st element       */
  502.     }
  503.   else
  504.     ce = *cp;                           /* pointer to 1st in group       */
  505.  
  506.   while (ce->next_element != NULL)      /* search last element           */
  507.     ce = ce->next_element;
  508.   ce->next_element = tp;                /* add new element to chain      */
  509.   }
  510.  
  511. /* ------------------------------------- */
  512. /* Build file description memory block   */
  513. /* ------------------------------------- */
  514. char *build_desc(FILE  *fi,
  515.                  char  *ibuf,
  516.                  char  **rp)
  517. {
  518.   char   *fd;                           /* pointer memory block with desc*/
  519.   char   *desc;                         /* string work pointers          */
  520.   char   buf2[MAXDESC];                 /* work buffers                  */
  521.   unsigned short int k;                 /* counter                       */
  522.  
  523.   desc = next_word(ibuf);               /* locate description            */
  524.   if (desc != NULL) {                   /* start of description found    */
  525.     for (k=0; desc[k]; ++k) {           /* search first CR/LF            */
  526.       if (desc[k]=='\r' || desc[k]=='\n') {
  527.         desc[k] = '\0';
  528.         break;
  529.         }
  530.       }
  531.     strcpy(buf2, desc);                 /* save desc in buf2             */
  532.     while (((*rp = fgets(ibuf, MAXDESC, fi)) != NULL) &&  /* next rcd    */
  533.            (ibuf[0] == ' ') &&          /* probably desc continuation    */
  534.            ((desc = next_word(ibuf)) != NULL)) {
  535.       for (k=0; desc[k]!='\0'; ++k) {
  536.         if (desc[k]=='\r' || desc[k]=='\n') {
  537.           desc[k] = '\0';
  538.           break;
  539.           }
  540.         }
  541.       if ((strlen(buf2) + k + 1) <= sizeof(buf2)) {  /* not too long     */
  542.         strcat(buf2," ");               /* single space                  */
  543.         strcat(buf2, desc);             /* concat desc to buf2           */
  544.         }
  545.       }
  546.     fd = malloc(strlen(buf2)+1);        /* obtain memory                 */
  547.     if (fd == NULL) {
  548.       fprintf(stderr, MSG_MEM, PROGNAME);  /* not enough memory          */
  549.       DosExit(0, 12);
  550.       }
  551.     else
  552.       strcpy(fd, buf2);                 /* store description             */
  553.     }
  554.   else                                  /* no description                */
  555.     fd = NULL;                          /* return value                  */
  556.   return(fd);                           /* return with pointer           */
  557.   }
  558.  
  559. /* ------------------------------------- */
  560. /* Assign description to file element(s) */
  561. /* ------------------------------------- */
  562. FILECHAIN *assign_desc(short int x,
  563.                                char  *filename,
  564.                                FILECHAIN **fa,
  565.                                DOWNPATH _HUGE *parea,
  566.                                char   *desc,
  567.                                short  int fpriv,
  568.                                unsigned short int bbsseq)
  569. {
  570.   short int    low,high,index;          /* indexes                       */
  571.   short int    b,n;                     /* counters                      */
  572.   unsigned short int dlb,dlt;           /* download flags in description */
  573.   FILECHAIN *tp;                /* ptr to file-info              */
  574.   char         dl_flags[5];             /* copy of first part description*/
  575.  
  576.   dlb = dlt = 0;                        /* flags off                     */
  577.   while (desc != NULL) {                /* only when real descr. present */
  578.     strncpy(dl_flags, desc, 4);         /* copy part of description      */
  579.     if (dl_flags[0] == '/') {           /* could be valid dl_flag        */
  580.       strupr(dl_flags);                 /* make all uppercase            */
  581.       if (dl_flags[1] == 'B' || dl_flags[2] == 'B')
  582.         dlb = 1;                        /* unlimited download bytes flag */
  583.       if (dl_flags[1] == 'T' || dl_flags[2] == 'T')
  584.         dlt = 1;                        /* unlimited download time flag  */
  585.       desc = next_word(desc);           /* shift the description pointer */
  586.       }
  587.     else                                /* not MAXIMUS dl-flag */
  588.       break;                            /* escape from while-loop */
  589.     }
  590.  
  591.   low  = 0;                             /* index of first entry          */
  592.   high = x-1;                           /* index of last entry           */
  593.   while (low <= high) {                 /* binary search in array        */
  594.     index = (high + low) / 2;           /* middle of interval            */
  595.     if ((b = wild_comp(fa[index]->fname,filename)) < 0)
  596.       low = index + 1;                  /* new low boundary              */
  597.     else if (b > 0)                     /* 'b'-value from previous 'if'  */
  598.       high = index - 1;                 /* new high boundary             */
  599.     else
  600.       break;                            /* equal: found                  */
  601.     }
  602.  
  603.   tp = NULL;                            /* init to 'not offline'         */
  604.   if (x < 1  ||                         /* no files in directory at all  */
  605.       wild_comp(fa[index]->fname,filename)) {  /* this one not in dir    */
  606.     tp = file_element(parea, NULL);     /* alloc new element             */
  607.     strcpy(tp->fname, filename);        /* copy filename to new element  */
  608.     tp->fdesc = (desc != NULL) ? desc : NDS; /* assign 'some' desc       */
  609.     tp->priv = fpriv;                   /* copy privilege                */
  610.     tp->fseq = bbsseq;                  /* copy FILES.BBS line number    */
  611.     tp->dl_b = dlb;                     /* copy download bytes flag      */
  612.     tp->dl_t = dlt;                     /* copy download time flag       */
  613.     if (oper_mode == VERBOSE)
  614.       fprintf(stdout," \t%s  %s\n", OFFLINE, filename); /* filename */
  615.     }
  616.   else {                                /* file found in directory       */
  617.     n = index;                          /* 'hit' and lower entries       */
  618.     while (n>=0 && wild_comp(fa[n]->fname,filename) == 0) {
  619.       if (fa[n]->fdesc == NULL) {       /* no description assigned yet   */
  620.         fa[n]->fdesc = (desc==NULL) ? NDS : desc;
  621.         fa[n]->parea = parea;           /* copy / overwrite area ptr     */
  622.         fa[n]->priv  = fpriv;           /* copy privilege                */
  623.         fa[n]->dl_b  = dlb;             /* copy download bytes flag      */
  624.         fa[n]->dl_t  = dlt;             /* copy download time flag       */
  625.         fa[n]->fseq  = bbsseq;          /* copy FILES.BBS line number    */
  626.         }
  627.       else if (strcmp(fa[n]->parea->name,parea->name))  /* diff. dir     */
  628.         tp = desc_dup(fa[n], desc, parea, fpriv, bbsseq, dlb, dlt); /*new*/
  629.       --n;                              /* next lower                    */
  630.       }
  631.     n = index + 1;                      /* higher entries                */
  632.     while (n<x && wild_comp(fa[n]->fname,filename) == 0) {
  633.       if (fa[n]->fdesc == NULL) {       /* no description assigned yet   */
  634.         fa[n]->fdesc = (desc==NULL) ? NDS : desc;
  635.         fa[n]->parea = parea;           /* copy / overwrite area ptr     */
  636.         fa[n]->priv  = fpriv;           /* copy privilege                */
  637.         fa[n]->dl_b  = dlb;             /* copy download bytes flag      */
  638.         fa[n]->dl_t  = dlt;             /* copy download time flag       */
  639.         fa[n]->fseq  = bbsseq;          /* copy FILES.BBS line number    */
  640.         }
  641.       else if (strcmp(fa[n]->parea->name,parea->name))  /* diff. dir     */
  642.         tp = desc_dup(fa[n], desc, parea, fpriv, bbsseq, dlb, dlt); /*new*/
  643.       ++n;                              /* next higher                   */
  644.       }
  645.     }
  646.   return(tp);                           /* return pointer to new(?)      */
  647.                                         /* element or NULL if not new    */
  648.   }
  649.  
  650. /* ---------------------------------------------- */
  651. /* Create duplicate file element with description */
  652. /* ---------------------------------------------- */
  653. FILECHAIN *desc_dup(FILECHAIN *fa,
  654.                             char *desc,
  655.                             DOWNPATH _HUGE *parea,
  656.                             short int fpriv,
  657.                             unsigned short int bbsseq,
  658.                             unsigned short int dlb,
  659.                             unsigned short int dlt)
  660. {
  661.   FILECHAIN *tp;                /* ptr to file-info              */
  662.  
  663.   tp = file_element(parea, NULL);       /* alloc new element             */
  664.   tp->wdate = fa->wdate;                /* copy file wrtie date          */
  665.   tp->wtime = fa->wtime;                /* copy file write time          */
  666.   tp->cdate = fa->cdate;                /* copy file create date         */
  667.   tp->ctime = fa->ctime;                /* copy file create time         */
  668.   tp->size  = fa->size;                 /* copy file size                */
  669.   tp->attr  = fa->attr;                 /* copy file attr                */
  670.   tp->fseq  = bbsseq;                   /* copy FILES.BBS line number    */
  671.   tp->priv  = fpriv;                    /* copy privilege                */
  672.   tp->dl_b  = dlb;                      /* copy download bytes flag      */
  673.   tp->dl_t  = dlt;                      /* copy download time flag       */
  674.   strcpy(tp->fname, fa->fname);         /* copy filename to new element  */
  675.   tp->fdesc = (desc != NULL) ? desc : NDS;  /* add pointer to desc.      */
  676.   return(tp);                           /* return pointer                */
  677.   }
  678.  
  679. /* ---------------------------------------- */
  680. /* Add single file-entry to file-chain      */
  681. /* returns: pointer to new element          */
  682. /* ---------------------------------------- */
  683. FILECHAIN *file_element(DOWNPATH _HUGE *parea,
  684. #ifndef __32BIT__
  685.                                 FILEFINDBUF *cf)
  686. #else
  687.                                 FILEFINDBUF3 *cf)
  688. #endif
  689. {
  690.   FILECHAIN *tp;                /* temporary-pointer             */
  691.  
  692.   tp = (FILECHAIN *)malloc(sizeof(FILECHAIN));
  693.   if (tp == NULL) {
  694.      fprintf(stderr, MSG_MEM, PROGNAME);  /* not enough memory           */
  695.      DosExit(0, 11);
  696.      }
  697.   memset(tp, '\0', sizeof(FILECHAIN)); /* whole struct zeroes    */
  698.   tp->next_element = NULL;              /* ptr to next                   */
  699.   tp->fseq  = 65535;                    /* default FILES.BBS line number */
  700.   tp->priv  = HIDDEN;                   /* unless FILES.BBS proves otherw*/
  701.   tp->fdesc = NULL;                     /* unless found in FILES.BBS     */
  702.   tp->fpath = NULL;                     /* explicit path in FILES.BBS    */
  703.   tp->parea = parea;                    /* copy pointer to area info     */
  704.   if (cf != NULL) {                     /* file-system info available    */
  705.     tp->wdate = cf->fdateLastWrite;
  706.     tp->wtime = cf->ftimeLastWrite;
  707.     if (file_time(cf->fdateCreation, cf->ftimeCreation) >
  708.         file_time(cf->fdateLastWrite, cf->ftimeLastWrite) ) {  /* HPFS   */
  709.       tp->cdate = cf->fdateCreation;    /* creation most recent          */
  710.       tp->ctime = cf->ftimeCreation;
  711.       }
  712.     else {                              /* otherwise and non-HPFS volumes*/
  713.       tp->cdate = cf->fdateLastWrite;
  714.       tp->ctime = cf->ftimeLastWrite;
  715.       }
  716.     tp->size  = cf->cbFile;
  717.     tp->attr  = cf->attrFile;
  718.     strncpy(tp->fname, cf->achName, MAXFN);
  719.     }
  720.   return(tp);
  721.   }
  722.  
  723. /* --------------------------------- */
  724. /* Build comment entry in file-chain */
  725. /* --------------------------------- */
  726. FILECHAIN *add_comment(char  *filename,
  727.                                DOWNPATH _HUGE *parea,
  728.                                char   *fdesc,
  729.                                short  int fpriv,
  730.                                unsigned short int bbsseq)
  731. {
  732.   FILECHAIN *tp;                /* ptr to file-info              */
  733.   char   *fd;                           /* ptr to file description       */
  734.   char   buf2[MAXDESC];                 /* work buffer                   */
  735.   unsigned short int k;                 /* counter                       */
  736.  
  737.   strncpy(buf2, fdesc, MAXDESC);        /* save desc in buf2             */
  738.   for (k=0; buf2[k]!='\0'; ++k)         /* scan work buffer              */
  739.     if (buf2[k]=='\r' || buf2[k]=='\n') { /* for CR/LF                   */
  740.       buf2[k] = '\0';                   /* replace by end-of-string      */
  741.       break;
  742.       }
  743.   tp = file_element(parea, NULL);       /* alloc new element             */
  744.   strncpy(tp->fname, filename, MAXFN);  /* EMPTY for comment             */
  745.   tp->priv = fpriv;                     /* privilege                     */
  746.   tp->fseq = bbsseq;                    /* FILES.BBS line number         */
  747.   tp->cmt  = 1;                         /* indicate as comment element   */
  748.   fd = malloc(k + 1);                   /* obtain memory for desc        */
  749.   if (fd == NULL) {
  750.     fprintf(stderr, MSG_MEM, PROGNAME);    /* not enough memory          */
  751.     DosExit(0, 12);
  752.     }
  753.   else {
  754.     strcpy(fd, buf2);                   /* store description             */
  755.     tp->fdesc = fd;                     /* pointer to desc               */
  756.     }
  757.   return(tp);                           /* return pointer                */
  758.   }
  759.  
  760. /* ------------------------------------------------------ */
  761. /* supply file-entry with explicit path spec in FILES.BBS */
  762. /* ------------------------------------------------------ */
  763. void  add_pathspec(char  *filespec,         /* asciiz filespec */
  764.                    FILECHAIN *tp)   /* pointer to file element */
  765. {
  766. #ifndef __32BIT__
  767.   FILESTATUS cf;                        /* file-info buffer              */
  768. #else
  769.   FILESTATUS3 cf;                       /* file-info buffer              */
  770. #endif
  771.   int  fn_off;                          /* offset filename in filespec */
  772.  
  773.   if
  774. #ifndef __32BIT__
  775.      ( DosQPathInfo(strupr(filespec), 1, (char *)&cf, sizeof(cf), 0L)
  776. #else
  777.      ( DosQueryPathInfo(strupr(filespec), 1, &cf, sizeof(cf))
  778. #endif
  779.            != 0) {
  780.     fprintf(stderr, "\tfile %s not found: %s\n", filespec);
  781.     return;                             /* return without info */
  782.     }
  783.   else {
  784.     fn_off = split_fname(filespec);     /* path size */
  785.     strncpy(tp->fname, filespec+fn_off, MAXFN);
  786.     strupr(tp->fname);                  /* filename in capitals */
  787.     tp->fname[MAXFN-1] = '\0';          /* ensure string termination */
  788.     tp->fpath = malloc(fn_off + 1);     /* mem for path */
  789.     if (tp->fpath != NULL) {            /* memory obtained */
  790.       strncpy(tp->fpath, strupr(filespec), fn_off);  /* copy path */
  791.       *(tp->fpath + fn_off) = '\0';     /* end of string */
  792.       }
  793.     tp->wdate = cf.fdateLastWrite;
  794.     tp->wtime = cf.ftimeLastWrite;
  795.     if (file_time(cf.fdateCreation, cf.ftimeCreation) >
  796.         file_time(cf.fdateLastWrite, cf.ftimeLastWrite) ) {  /* HPFS   */
  797.       tp->cdate = cf.fdateCreation;    /* creation most recent          */
  798.       tp->ctime = cf.ftimeCreation;
  799.       }
  800.     else {                              /* otherwise and non-HPFS volumes*/
  801.       tp->cdate = cf.fdateLastWrite;
  802.       tp->ctime = cf.ftimeLastWrite;
  803.       }
  804.     tp->size  = cf.cbFile;
  805.     tp->attr  = cf.attrFile;
  806.     return;                             /* back to caller     */
  807.     }
  808.   }
  809.  
  810. /* ----------------------------------------------------------- */
  811. /* Release memory occupied by orphan entries.                  */
  812. /* If first element contains an orphan it will not be removed! */
  813. /* ----------------------------------------------------------- */
  814. unsigned short int free_orphan()
  815. {
  816.   unsigned short int  orp_cnt;          /* removed orphan counter        */
  817.   FILECHAIN *ca,*cb;            /* current and next chain pointer*/
  818.  
  819.   orp_cnt = 0;                          /* initial orphan count          */
  820.   if ((ca=first_element) != NULL) {     /* any file elements in chain    */
  821.     while ((cb=ca->next_element) != NULL) {  /* all elements (but first) */
  822.       if (cb->priv >= HIDDEN) {         /* probably orphan?              */
  823.         ca->next_element = cb->next_element; /* new ptr in current elemen*/
  824.         free(cb);                       /* free memory block             */
  825.         ++orp_cnt;                      /* one more dropped              */
  826.         }                               /* note: do not shift current    */
  827.       else                              /* not an orphan                 */
  828.         ca = cb;                        /* shift +1 current element      */
  829.       }
  830.     }                                   /* only orphans                  */
  831.   return(orp_cnt);                      /* report # of removed orphans   */
  832.   }
  833.  
  834. /* ---------------------------------------------------- */
  835. /* Combine consecutive comment lines to a single string */
  836. /* return the number of freed chain elements            */
  837. /* ---------------------------------------------------- */
  838. unsigned short int combine_comments(void)
  839. {
  840.   unsigned short int  cmt_cnt;          /* freed elements count          */
  841.   FILECHAIN *ca,*cb;            /* current and next chain pointer*/
  842.   char *new;                            /* ptr to combined comments      */
  843.   unsigned int k,l;                     /* string lengths                */
  844.  
  845. #if defined(__DEBUG__)
  846.   dump_file_chain(first_element, "begin combine_comments()");
  847. #endif
  848.   cmt_cnt = 0;                          /* initial freed elements count  */
  849.   if ((ca=first_element) != NULL) {     /* any elements in chain         */
  850.     while ((cb=ca->next_element) != NULL) {  /* all elements             */
  851.       if (ca->fname[0] == '\0'  &&      /* comment #1                    */
  852.           cb->fname[0] == '\0'  &&      /* comment #2                    */
  853.           cb->fseq == ca->fseq+1) {     /* consecutive lines in FILES.BBS*/
  854.         k = strlen(ca->fdesc);          /* take length of 1st comment    */
  855.         l = strlen(cb->fdesc);          /* take length of 2nd comment    */
  856.         if ((new = (char *)malloc(k+l+2)) != NULL) {  /* mem obtained    */
  857.           strcpy(new,ca->fdesc);        /* copy 1st comment              */
  858.           strcat(new,"\n");             /* insert newline                */
  859.           strcat(new,cb->fdesc);        /* copy 2nd comment              */
  860.           free(ca->fdesc);              /* release 1st old comment       */
  861.           free(cb->fdesc);              /* release 2nd old comment       */
  862.           ca->fdesc = new;              /* ptr to combined desc in cur el*/
  863.           ca->next_element = cb->next_element; /* new ptr in cur el.     */
  864.           free(cb);                     /* release 2nd chain-element     */
  865.           ++cmt_cnt;                    /* update counter                */
  866.           }
  867.         else
  868.           ca = cb;                      /* no memory: proceed            */
  869.         }
  870.       else                              /* not 2 consecutive comments    */
  871.         ca = cb;                        /* shift +1 current element      */
  872.       }
  873.     }                                   /* only orphans                  */
  874. #if defined(__DEBUG__)
  875.   dump_file_chain(first_element, "end combine_comments()");
  876. #endif
  877.   return(cmt_cnt);                      /* report # of removed elements  */
  878.   }
  879.  
  880. /* ----------------------------------------- */
  881. /* Check if string could be a filename       */
  882. /* Only needed as distiction form decription */
  883. /* Returns NULL if probably not a filespec.  */
  884. /* ----------------------------------------- */
  885. char *parse_fname(char *buf)
  886. {
  887.   char  c0;                             /* first character               */
  888.  
  889.   c0 = buf[0];                          /* take first character on line  */
  890.   if ( strlen(buf) < 2  ||              /* empty line                    */
  891.        c0 <= ' '  ||
  892.        c0 == '\"' ||
  893.       (c0 >= '+'  && c0 <= '/')  ||
  894.       (c0 >= ':'  && c0 <= '>')  ||
  895.       (c0 >= '['  && c0 <= ']')  ||
  896.        c0 == '|'  ||
  897.        c0 >= 128)
  898.     return(NULL);                       /* probably not a filename       */
  899.   else                                  /* now check for pathspec        */
  900.     return(buf);
  901.   }
  902.  
  903. /* ----------------------------------- */
  904. /* Split path (if any) from filespec.  */
  905. /* Returns offset to filename in buf.  */
  906. /* ----------------------------------- */
  907. int  split_fname(char *buf)
  908. {
  909.   char  *pFile;                         /* pointer                       */
  910.   char  tempbuf[2048];                  /* work buffer                   */
  911.  
  912.   strcpy(tempbuf, asciiz(buf));         /* copy first 'word'             */
  913.   pFile = strrchr(tempbuf,'\\');        /* search last backslash         */
  914.   if (pFile == NULL)                    /* no directory spec found       */
  915.     pFile = strrchr(tempbuf,':');       /* search last colon             */
  916.   if (pFile == NULL)                    /* also no drive spec found      */
  917.     return(0);                          /* zero: no explicit path spec'd */
  918.   else                                  /* explicit pathspec found       */
  919.     return(pFile - tempbuf + 1);        /* offset to filename in buf     */
  920.   }
  921.  
  922.  
  923. /* ------------------------------------- */
  924. /* Determine if area is within selection */
  925. /* ------------------------------------- */
  926. int  area_selection(char *name,
  927.                     char sel_array[][MAXANAME])
  928. {
  929.   int   result;
  930.   short int i;
  931.  
  932.   if (area_IN_EX) {                     /* area selection specified      */
  933.     result = (area_IN_EX < 0) ? 1 : 0;  /* default not found: IN=0 EX=1  */
  934.     for (i=0; strcmp(sel_array[i], EMPTY); i++) {
  935.       if (!strnicmp(sel_array[i], name, strlen(sel_array[i]))) {
  936.         result = (area_IN_EX < 0) ? 0 : 1;  /* found: IN=1 EX=0          */
  937.         break;                          /* escape from while-loop        */
  938.         }
  939.       }
  940.     }
  941.   else
  942.     result = 1;                         /* no selections: all            */
  943.   return(result);                       /* return selection result       */
  944.   }
  945.  
  946. /* =================================================== */
  947. /* Compare for sort of area-array on download pathname */
  948. /* =================================================== */
  949. int  sort_path(const void *p,
  950.                const void *q)
  951. {
  952.   int  rc;
  953.   DOWNPATH _HUGE *x, *y;
  954.   x = (DOWNPATH _HUGE *)p;
  955.   y = (DOWNPATH _HUGE *)q;
  956.   if ((rc = stricmp(x->pname, y->pname)) == 0)  /* download pathname     */
  957.     rc = stricmp(x->name, y->name);     /* area name                     */
  958.   return(rc);
  959.   }
  960.  
  961.  
  962. #if defined(__DEBUG__)
  963. /* =============== */
  964. /* Dump area array */
  965. /* =============== */
  966. int dump_area_array(DOWNPATH _HUGE *aa,  /* pointer to array     */
  967.                     short int m,                /* number of elements    */
  968.                     char *id)                   /* log id                */
  969. {
  970.   short int i;
  971.   FILE *log;
  972.  
  973.   log = fopen("downsort.log","a");      /* append!                       */
  974.   fprintf(log,"\n");                    /* newline                       */
  975.   sep_line(log,'═',79);                 /* separate from previous append */
  976.   fprintf(log,"(%s) %s\n", today, id);  /* timestamp + id                */
  977.   flushall();
  978.   for (i=0; i<m; i++) {
  979.     fprintf(log,"\n%4d. bytecount=%10lu priv=%5d anum=%d filecount=%5u\n",
  980.         i+1,
  981.         aa[i].byte_count,
  982.         aa[i].priv,
  983.         aa[i].anum,
  984.         aa[i].file_count);
  985.     fprintf(log," name %s\nename %s\npname %s\nf_bbs %s\n desc %s\n",
  986.         aa[i].name,
  987.         aa[i].ename,
  988.         aa[i].pname,
  989.         aa[i].filesbbs,
  990.         aa[i].adesc);
  991.     fprintf(log,"newst %s\n",
  992.         (aa[i].newest != NULL) ? aa[i].newest->fname : "-");
  993.     flushall();                         /* write buffers before continue */
  994.     }
  995.   fclose(log);
  996.   return(i);
  997.   }
  998.  
  999. /* =============== */
  1000. /* Dump file chain */
  1001. /* =============== */
  1002. int dump_file_chain(FILECHAIN *f,       /* pointer to chain      */
  1003.                     char *id)                   /* log id                */
  1004. {
  1005.   FILE *log;
  1006.   unsigned short int fc;                /* element count                 */
  1007.   FILECHAIN *fe;                        /*                               */
  1008.  
  1009.   log = fopen("downsort.log","a");      /* append!                       */
  1010.   fprintf(log,"\n");                    /* newline                       */
  1011.   sep_line(log,'═',79,0);               /* separate from previous append */
  1012.   fprintf(log,"(%s) %s\n\n", today, id);  /* timestamp + id              */
  1013.   flushall();                           /* force physical write(s)       */
  1014.   fe = f;                               /* pointer to first element      */
  1015.   fc = 0;                               /* counter=0                     */
  1016.   while(fe != NULL) {
  1017.     if (fe->fname[0] != '\0') {
  1018.       fprintf(log,"%*.*s", MAXANAME, MAXANAME, fe->parea->name); /* area */
  1019.       fprintf(log," %s ", fe->fname);   /* filename                      */
  1020.       }
  1021.     fprintf(log,"%s\n",
  1022.                 (fe->fdesc != NULL) ? fe->fdesc : EMPTY);  /* file desc  */
  1023.     fc++;
  1024.     fe = fe->next_element;
  1025.     }
  1026.   fprintf(log,"\nChain_element_count = %u\n\n", fc);
  1027.   fclose(log);
  1028.   return(fc);
  1029.   }
  1030. #endif
  1031.  
  1032.